#pragma once

#include <AVUIUncommonField.h>
#include <AVUIItemStructList.h>

namespace AVUI {

class DependencyObject;
class HybridDictionary;

/// <summary>Defines a contract for how names of elements should be accessed within a particular namescope, and how to enforce uniqueness of names within that scope. </summary>
class INameScope
{
public:
    /// <summary>Returns an object that has the provided identifying name. </summary>
    /// <returns>The object, if found. Returns null if no object of that name was found.</returns>
    /// <param name="name">The name identifier for the object being requested.</param>
    virtual Object* FindName(String* pName) = 0;

    /// <summary>Registers the provided name into the current namescope. </summary>
    /// <param name="name">Name to register.</param>
    /// <param name="scopedElement">The specific element that the provided <paramref name="name" /> refers to.</param>
    virtual void RegisterName(String* pName, Object* pScopedElement) = 0;

    /// <summary>Unregisters the provided name from the current namescope. </summary>
    /// <param name="name">The name to unregister.</param>
    virtual void UnregisterName(String* pName) = 0;

    /// <summary>WPFG Deviation - Returns the object-derived element providing the INameScope service.</summary>
    virtual Object* get_Object() = 0;
};

/// <summary>Implements base support for the <see cref="T:System.Windows.Markup.INameScope" /> methods that store or retrieve name-object mappings into a particular namescope, and adds attached property support to make it simpler to get or set identifier namescope information dynamically at the element level.</summary>
class NameScope : public Object, public INameScope
{
public:
    DECLARE_ELEMENT(NameScope, Object);

#pragma region Public Methods

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.NameScope" /> class.</summary>
    NameScope() { }

    /// <summary>Returns the corresponding object in a namescope, based on a provided name string.</summary>
    /// <returns>The requested object. Can return null if <paramref name="name" /> was provided as null or empty string, or if no matching object was found.</returns>
    /// <param name="name">Mapped name of the object to retrieve.</param>
    Object* FindName(String* pName) AVUI_OVERRIDE;

    /// <summary>Provides the attached property get accessor for the <see cref="P:System.Windows.NameScope.NameScope" /> attached property.</summary>
    /// <returns>A namescope, as an <see cref="T:System.Windows.Markup.INameScope" /> instance.</returns>
    /// <param name="dependencyObject">The object to get the namescope from.</param>
    static INameScope* GetNameScope(DependencyObject* pDependencyObject);

    /// <summary>Provides the attached property set accessor for the <see cref="P:System.Windows.NameScope.NameScope" /> attached property.</summary>
    /// <param name="dependencyObject">Object to change namescope for.</param>
    /// <param name="value">The new namescope, using an interface cast.</param>
    static void SetNameScope(DependencyObject* pDependencyObject, INameScope* pValue);
    DECLARE_DEPENDENCY_PROPERTY(NameScope);

    /// <summary>Registers a new name-object pair into the current namescope.</summary>
    /// <param name="name">The name to use for mapping the given object.</param>
    /// <param name="scopedElement">The object to be mapped to the provided name.</param>
    /// <exception cref="T:System.NullReferenceException">Either <paramref name="name" /> or <paramref name="scopedElement" /> was provided as null.</exception>
    /// <exception cref="T:System.ArgumentException">The <paramref name="name" /> was provided as empty string- or -The <paramref name="name" /> provided was rejected by the parser, because it contained characters that are invalid for a XAML name- or -The <paramref name="name" /> provided would have resulted in a duplicate name registration.</exception>
    void RegisterName(String* pName, Object* pScopedElement);

    /// <summary>Removes a name-object mapping from the namescope.</summary>
    /// <param name="name">The name of the mapping to remove.</param>
    /// <exception cref="T:System.ArgumentException">The <paramref name="name" /> was provided as empty string.- or -The <paramref name="name" /> provided had not been registered.</exception>
    void UnregisterName(String* pName);

    /// <summary>WPFG Deviation - Returns the object-derived element providing the INameScope service.</summary>
    virtual Object* get_Object() { return this; }

#pragma endregion Public Methods

#pragma region Internal Methods

    static INameScope* NameScopeFromObject(Object* pObj);

#pragma endregion Internal Methods

private:

#pragma region Private Methods
    static void StaticConstructor();
#pragma endregion Private Methods

#pragma region Private Fields
    TRefCountedPtr<HybridDictionary> m_pNameMap;
#pragma endregion Private Fields

};

}; // namespace AVUI
